package data_operater

import (
	"context"
	"fmt"
	"reflect"
	"strconv"
)

type SetterDataProvider func(ctx context.Context, original interface{}, fieldData interface{}) (map[string]interface{}, error)

type Setter interface {
	Set(ctx context.Context, originalData interface{}, currentNodeData interface{}, dataProvider SetterDataProvider) error
	SetNext(next Setter)
	GetType() SetterType
	GetFieldName() string
	SetChild(child Setter) error
	GetChild() Setter
	SetChildNext(child Setter) error
}

func setObjData(ctx context.Context, originalData interface{}, vData reflect.Value, dataProvider SetterDataProvider) error {
	if vData.Kind() != reflect.Map && vData.Kind() != reflect.Struct {
		vData = vData.Elem()
	}
	switch vData.Kind() {
	case reflect.Map:
		currentNodeData := make(map[string]interface{})
		for _, k := range vData.MapKeys() {
			currentNodeData[k.String()] = vData.MapIndex(k).Interface()
		}
		sourceData, err := dataProvider(ctx, originalData, currentNodeData)
		if err != nil {
			return err
		}
		for k, v := range sourceData {
			vData.SetMapIndex(reflect.ValueOf(k), reflect.ValueOf(v))
		}
	default:
		return fmt.Errorf("仅支持为map设置值")
	}
	return nil
}

func NewPropSetter(fieldName string) Setter {
	return &PropSetter{
		fieldName: fieldName,
		next:      nil,
	}
}

type PropSetter struct {
	fieldName string
	next      Setter
	child     Setter
}

func (p *PropSetter) SetChildNext(child Setter) error {
	if p.child != nil {
		return p.child.SetChildNext(child)
	}
	p.child.SetNext(child)
	return nil
}

func (p *PropSetter) GetChild() Setter {
	return p.child
}

func (p *PropSetter) SetChild(child Setter) error {
	if p.child != nil {
		return p.child.SetChild(child)
	}
	p.child = child
	return nil
}

func (p *PropSetter) GetFieldName() string {
	return p.fieldName
}

func (p *PropSetter) Set(ctx context.Context, originalData interface{}, currentNodeData interface{}, dataProvider SetterDataProvider) error {
	vData, ok := currentNodeData.(reflect.Value)
	if !ok {
		v := reflect.ValueOf(currentNodeData)
		if v.Kind() != reflect.Map && v.Kind() != reflect.Ptr {
			return fmt.Errorf("传入的参数必须是指针类型")
		}
		vData = v
	}
	var vNextData reflect.Value
	if vData.Kind() != reflect.Struct && vData.Kind() != reflect.Map {
		vData = vData.Elem()
	}
	switch vData.Kind() {
	case reflect.Struct:
		vNextData = vData.FieldByName(p.GetFieldName())
		// 把同级的对象只都丢到ctx中，方便后面获取
		tData := vData.Type()
		for i := 0; i < tData.NumField(); i++ {
			ctx = context.WithValue(ctx, tData.Field(i).Name, vData.Field(i).Interface())
		}
	case reflect.Map:
		vNextData = vData.MapIndex(reflect.ValueOf(p.GetFieldName()))
		// 把同级的对象只都丢到ctx中，方便后面获取
		for _, vKey := range vData.MapKeys() {
			ctx = context.WithValue(ctx, vKey.Interface(), vData.MapIndex(vKey).Interface())
		}
	}
	if p.child != nil {
		// 有子组件，让子组件去设值
		return p.child.Set(ctx, originalData, vNextData, dataProvider)
	}
	if p.next != nil {
		// 有下个节点，则获取当前节点的数据引用，传递到下个节点里
		return p.next.Set(ctx, originalData, vNextData, dataProvider)
	}
	return setObjData(ctx, originalData, vNextData, dataProvider)
}

func (p *PropSetter) SetNext(next Setter) {
	p.next = next
}

func (p *PropSetter) GetType() SetterType {
	return SetterTypeProp
}

// ========== array

func NewArraySetter(index string) (Setter, error) {
	if index != "" {
		if numIndex, err := strconv.Atoi(index); err == nil {
			return &arraySetter{index: numIndex}, nil
		} else {
			return nil, fmt.Errorf("数组下标参数错误：%s", index)
		}
	}
	return &arraySetter{index: -1}, nil
}

type arraySetter struct {
	index int
	next  Setter
	child Setter
}

func (a *arraySetter) SetChildNext(child Setter) error {
	if a.child != nil {

		return a.child.SetChildNext(child)
	}
	a.child = child
	return nil
}

func (a *arraySetter) GetChild() Setter {
	return a.child
}

func (a *arraySetter) SetChild(child Setter) error {
	if a.child != nil {
		return a.child.SetChild(child)
	}
	a.child = child
	return nil
}

func (a *arraySetter) Set(ctx context.Context, originalData interface{}, currentNodeData interface{}, dataProvider SetterDataProvider) error {

	vData, ok := currentNodeData.(reflect.Value)
	if !ok {
		return fmt.Errorf("传入的参数必须是数组引用")
	}
	if vData.Kind() != reflect.Array && vData.Kind() != reflect.Slice {
		if !vData.IsValid() {
			return fmt.Errorf("数组解析出错")
		}
		vData = vData.Elem()
		if vData.Kind() != reflect.Array && vData.Kind() != reflect.Slice {
			return fmt.Errorf("数组解析出错")
		}
	}

	if a.index > -1 {
		vRowData := vData.Index(a.index)
		if a.next != nil {
			// 存在后续节点，由后续节点设置值
			return a.next.Set(ctx, originalData, vRowData, dataProvider)
		}
		// 没有后继节点，则把数据设置到当前对象上
		return setObjData(ctx, originalData, vRowData, dataProvider)
	} else {
		for i := 0; i < vData.Len(); i++ {
			if a.next != nil {
				err := a.next.Set(ctx, originalData, vData.Index(i), dataProvider)
				if err != nil {
					return err
				}
			} else if a.child != nil {
				err := a.child.Set(ctx, originalData, vData.Index(i), dataProvider)
				if err != nil {
					return err
				}
			} else {
				err := setObjData(ctx, originalData, vData.Index(i), dataProvider)
				if err != nil {
					return err
				}
			}

		}
	}
	return nil
}

func (a *arraySetter) SetNext(next Setter) {
	a.next = next
}

func (a *arraySetter) GetType() SetterType {
	return SetterTypeArray
}

func (a *arraySetter) GetFieldName() string {
	return ""
}
